package com.gitee.apanlh.util.algorithm.digest;

import com.gitee.apanlh.exp.DigestException;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.check.CheckImport;
import com.gitee.apanlh.util.check.CheckLibrary;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.valid.Assert;
import org.bouncycastle.crypto.digests.SHA3Digest;

/**
 * 	SHA摘要算法(采用BouncyCastle开源库实现)
 * 	<br>使用更多摘要算法请到{@link DigestUtils}类中查看
 * 	<br>SHA-3散列算法
 * 	
 * 	@author Pan
 */
public class SHA3 extends CustomDigestAbstract implements CheckDigestType {
	
	static {
		CheckImport.library(CheckLibrary.BOUNCY_CASTLE);
	}
	
	/** 摘要类型 */ 
	private DigestType digestType;
	
	/** SHA3摘要 */
	private SHA3Digest digest;
	
	/**
	 * 	默认构造函数
	 * 	<br>默认采用SHA-3/256
	 * 	
	 * 	@author Pan
	 */
	public SHA3() {
		this(DigestType.SHA3_256);
	}
	
	/**
	 * 	构造函数
	 * 	<br>自定义指定SHA2范围的摘要类型
	 * 	
	 * 	@author Pan
	 * 	@param 	digestType		摘要类型
	 * 	@throws DigestException 如果未找到对应摘要算法则抛出
	 */
	public SHA3(DigestType digestType) {
		this.digestType = digestType;
		check();
		this.digest = new SHA3Digest(ClassConvertUtils.toInt(StringUtils.subStr(digestType.getAlgorithm(), 5)));
	}
	
	@Override
	public void check() throws DigestException {
		if (!Eq.enumsOr(this.digestType, 
				DigestType.SHA3_224,
				DigestType.SHA3_256, 
				DigestType.SHA3_384, 
				DigestType.SHA3_512)) {
			throw new DigestException("digest type error cause: expected type[{}] but actual type is[{}]", "SHA3-224/SHA3-256/SHA3-384/SHA3-512", this.digestType.getAlgorithm());
		}
	}
	
	@Override
	public byte[] hash(byte[] content) {
		Assert.isNotEmpty(content);
		
		digest.update(content, 0, content.length);
		byte[] bytes = new byte[digest.getDigestSize()];
		digest.doFinal(bytes, 0);
		return bytes;
	}
	
	/**	
	 * 	构建SM3摘要
	 * 	
	 * 	@return	SHA3
	 */
	public static SHA3 create() {
		return create(DigestType.SHA3_256);
	}
	
	/**	
	 * 	构建SM3摘要
	 * 	<br>自定义摘要类型
	 * 	
	 * 	@param 	digestType	摘要类型
	 * 	@return	SHA3
	 */
	public static SHA3 create(DigestType digestType) {
		return new SHA3(digestType);
	}
}
